package com.senni;

import com.senni.annotation.EnableFeign;
import com.senni.annotation.FeignClient;
import com.senni.boot.BootStrap;
import com.senni.config.CommonFeignConfiguration;
import com.senni.config.FeignCommonContract;
import feign.Feign;
import feign.InvocationHandlerFactory;
import feign.Logger;
import feign.codec.Decoder;
import feign.codec.Encoder;
import lombok.SneakyThrows;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Configuration
public class OpenFeignRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryPostProcessor {
    private static List<Class> classList=new ArrayList<>();
    FeignCommonContract feignCommonContract=new FeignCommonContract();

    @SneakyThrows
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableFeign.class.getName()));
        if(annotationAttributes!=null){
            String type = annotationAttributes.getString("type");
            OpenFeignScanner openFeignScanner=new OpenFeignScanner(registry);
            String[] values = annotationAttributes.getStringArray("value");
            if(values.length==1&& StringUtils.isEmpty(values[0])){
                String className = importingClassMetadata.getClassName();
                int i = className.lastIndexOf(".");
                values[0]=className.substring(0,i);
            }
            if("LOCAL".equalsIgnoreCase(type)){
                Set<BeanDefinitionHolder> beanDefinitionHolders = openFeignScanner.doScan(values);
                for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
                    registry.registerBeanDefinition(beanDefinitionHolder.getBeanName(),beanDefinitionHolder.getBeanDefinition());
                }

            }else{
                classList = openFeignScanner.doScanAndNewProxy(values);
            }
        }
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        for (Class aClass : classList) {
            Object instant = newInstant(aClass);
            if(instant==null){
                continue;
            }
            String beanName=productBeanName(aClass);
            configurableListableBeanFactory.registerSingleton(beanName,instant);
        }
    }
    private Object newInstant(Class aClass){
        FeignClient annotation = (FeignClient) aClass.getAnnotation(FeignClient.class);
        if(annotation==null){
            return null;
        }
        Decoder decoder=null;
        Encoder encoder=null;
        InvocationHandlerFactory invocationHandlerFactory=new InvocationHandlerFactory.Default();
        String url = BootStrap.GLOBAL.getProperty("feignUrl") +annotation.value();

        Class<? extends CommonFeignConfiguration> configuration = annotation.configuration();
        try {
            CommonFeignConfiguration abstractFeignConfiguration = configuration.newInstance();
            decoder=abstractFeignConfiguration.decoder();
            encoder=abstractFeignConfiguration.encoder();
            invocationHandlerFactory = abstractFeignConfiguration.invocationHandlerFactory();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        //todo
        return Feign.builder()
                .contract(feignCommonContract)
                .logger(new Logger.JavaLogger(OpenFeignRegistrar.class.getName()))
                .logLevel(Logger.Level.FULL)
                .encoder(encoder)
                .invocationHandlerFactory(invocationHandlerFactory)
                .decoder(decoder)
                .target(aClass, url);
    }
    private String productBeanName(Class clazz){
        String simpleName = clazz.getSimpleName();
        String firstName = simpleName.substring(0, 1).toLowerCase();
        String newName=firstName+simpleName.substring(1);
        return newName;
    }



}